#include "firgamewnd.h"
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>


FIRGameWnd::FIRGameWnd(QWidget *parent)
    : QFrame(parent) //继承于QFrame
{
    setMinimumSize((chessColumes + 1) * rectWidth, (chessRows + 1) * rectHeight);

    mPos = QPoint(-1,-1);    //最后落下的棋子的坐标初始化(-1,-1)
    mBlack = true;           //下一颗所下棋子的颜色，初始黑棋

    mClient = new Client;    //创建客户端
    connect(mClient, &Client::sigOtherUserMove,this, &FIRGameWnd::slotOtherUserMove);    //客户端的其他玩家行动信号连接游戏窗口的槽函数
    connect(mClient, &Client::sigNewGame,this, &FIRGameWnd::slotNewGame);                //客户端的新游戏信号连接游戏窗口的槽函数

    //转发信号，给MainWindow处理
    connect(mClient, &Client::sigOutput,this, &FIRGameWnd::sigOutput);                   //客户端的TextEdit输出text信号连接游戏窗口的信号
    connect(mClient, &Client::sigUpdateRoomState,this, &FIRGameWnd::sigUpdateRoomState); //客户端的更新房间状态信号连接游戏窗口的信号
}

void FIRGameWnd::Connect(QString ip, int port, int room)  //调用客户端ConnectToServer函数，传参主窗口上的ip，端口，房间号
{
    mClient->ConnectToServer(ip, port, room);
}

void FIRGameWnd::Say(QString text) //调用客户端SendMsg_Say函数，传参输入框的text
{
    mClient->SendMsg_Say(text); //TCP通信
}

void FIRGameWnd::Output(QString text) //发送输出信号（客户端调用）
{
    emit sigOutput(text);        //发送TextEdit输出text信号（主窗口接收）
}

void FIRGameWnd::GetRoomState(QList<ROOM_STATE> &state) //调用客户端GetRoomState函数，传参房间状态列表
{
    mClient->GetRoomState(state);
}

void FIRGameWnd::slotNewGame() //新游戏槽函数
{
    mItems.clear();        //棋子容器清空
    mPos = QPoint(-1,-1);  //初始化最后落下的棋子的坐标
    mBlack = true;         //黑棋
}

void FIRGameWnd::paintEvent(QPaintEvent *e) //重写绘图事件
{
    DrawChessboard();      //画棋盘
    DrawItems();           //画棋子
    DrawItemWithMouse();   //画棋子鼠标

    update();
}

void FIRGameWnd::DrawChessboard() //画棋盘
{
    QPainter painter(this);                               //创建画家
    painter.setRenderHint(QPainter::Antialiasing, true);  //设置反走样，不同的颜色强度绘制边框以减少视觉扭曲
    painter.setBrush(Qt::darkYellow);                     //暗黄色刷子，画填充颜色
    painter.setPen(QPen(QColor(Qt::black),2));            //黑色笔，粗细为2，画边框

    for (int i = 0;i<chessColumes; i++) {                   //20*20个画矩形格子，左上角起点为一半格子宽高的坐标
        for (int j = 0; j<chessRows; j++) {
            painter.drawRect( (i+0.5)*rectWidth,(j+0.5)*rectHeight,rectWidth,rectHeight);
        }
    }
}

void FIRGameWnd::DrawItems() //画棋子
{
    QPainter painter(this);                               //创建画家
    painter.setPen(QPen(QColor(Qt::transparent)));        //设置画笔透明

    for (int i = 0; i<mItems.size(); i++) {
        FIRItem item = mItems[i];
        if (item.mPt == mPos) {                     //棋子坐标 == 最后落下的棋子的坐标
            painter.setPen(QPen(QColor("#ff3333"),2,Qt::SolidLine)); //画笔，红边
            if (item.mBlack) {
                painter.setBrush(Qt::black);                         //黑色设置黑画刷
            }
            else {
                painter.setBrush(Qt::white);                         //白色设置白画刷
            }
            DrawChessAtPoint(painter,item.mPt);                      //在棋盘上画棋子
            painter.setPen(QPen(QColor(Qt::transparent)));           //设置画笔透明
            continue;
        }
        if (item.mBlack) {                   //非最后落下的棋子，没有红边
            painter.setBrush(Qt::black);
        }
        else {
            painter.setBrush(Qt::white);
        }
        DrawChessAtPoint(painter,item.mPt); //在棋盘上画棋子
    }
}

void FIRGameWnd::DrawChessAtPoint(QPainter& painter,QPoint& pt) //在棋盘上画棋子
{
    QPoint ptCenter((pt.x()+0.5)*rectWidth,(pt.y()+0.5)*rectHeight);  //棋子坐标（0,0）转换成在棋盘上的坐标（）
    painter.drawEllipse(ptCenter,rectWidth / 2,rectHeight / 2);       //画圆形棋子，圆心半径
}

void FIRGameWnd::DrawItemWithMouse() //画棋子鼠标
{
    QPainter painter(this);                         //创建画家
    painter.setPen(QPen(QColor(Qt::transparent)));  //设置画笔透明

    if (mClient->IsBlack()) {                        //客户端返回棋子颜色
        painter.setBrush(Qt::black);
    }
    else {
        painter.setBrush(Qt::white);
    }
    //光标坐标绘制成棋子摸样
    painter.drawEllipse(mapFromGlobal(QCursor::pos()), rectWidth / 2, rectHeight / 2);  //全局坐标系下的点转换为相对于对象本身坐标系下的点

}

void FIRGameWnd::mousePressEvent(QMouseEvent * e) //重写鼠标按压事件
{
    if (mClient->IsBlack()) {  //客户端返回黑棋
        if (!mBlack) {         //但下一个棋子应该由白棋下
            return;
        }
    }
    else {                     //客户端返回白棋
        if (mBlack) {          //但下一个棋子应该由黑棋下
            return;
        }
    }

    QPoint pt;
    pt.setX( (e->pos().x() ) / rectWidth);   //鼠标位置坐标转成棋子坐标（1,1）
    pt.setY( (e->pos().y() ) / rectHeight);

    for (int i = 0; i < mItems.size(); i++) {
        FIRItem item = mItems[i];
        if (item.mPt == pt) {
            //已有棋子
            return;
        }
    }
    mPos = pt;                             //最后落下的棋子的坐标 = 本次落子
    mClient->SendMsg_Move(pt.x(),pt.y());  //执行行动落子

    FIRItem item(pt, mBlack);
    mItems.append(item);                  //本次的落子加入到棋子容器

    int nLeft =			CountNearItem(item,QPoint(-1,0));  //这个棋子的八个方向的连续个数
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ((nLeft + nRight) >= 4 ||            //判断胜利
        (nLeftUp + nRightDown) >= 4 ||
        (nUp + nDown) >= 4 ||
        (nRightUp + nLeftDown) >= 4 ) {
        if (mBlack == mClient->IsBlack()) {
            //赢的一方通知服务器自己赢了
            mClient->SendMsg_Success();
        }

        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(this, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);
        mItems.clear();
        //NewGame();
        return;
    }
    mBlack = !mBlack;  //棋子换颜色
}

int FIRGameWnd::CountNearItem(FIRItem item,QPoint ptDirection) //一个棋子在一个方向上的连续的个数
{
    int nCount = 0;
    item.mPt += ptDirection;

    while (mItems.contains(item)) {  //查找
        nCount++;
        item.mPt += ptDirection;
    }
    return nCount;
}

void FIRGameWnd::slotOtherUserMove(int x, int y) //其他玩家行动槽函数
{
    mPos = QPoint(x, y); //最后落下的棋子的坐标 = 其他玩家行动落子

    QPoint pt(x, y);
    FIRItem item(pt, mBlack);
    mItems.append(item); //本次落子加入棋子容器

    int nLeft =			CountNearItem(item,QPoint(-1,0));  //这个棋子的八个方向的连续个数
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ( (nLeft + nRight) >= 4 ||                           //判断胜利
        (nLeftUp + nRightDown) >= 4 ||
        (nUp + nDown) >= 4 ||
        (nRightUp + nLeftDown) >= 4 ) {
        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(nullptr, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);

        mItems.clear();
        //NewGame();
        return;
    }


    mBlack = !mBlack; //棋子换颜色
    update();
}
